#pragma once


#include <string>
#include <utility>

namespace cpp{

	template< class DelimT,
	class CharT = char,
	class Traits = std::char_traits < CharT >>
	class ostream_joiner
	{
	public:
		using char_type = CharT;
		using traits_type = Traits;
		using ostream_type = std::basic_ostream<CharT, Traits>;
		using value_type = void;
		using difference_type = void;
		using pointer = void;
		using reference = void;
		using iterator_category = std::output_iterator_tag;

		ostream_joiner(ostream_type& stream, const DelimT& delimiter)
			:_out_stream(std::addressof(stream))
			, _delimt(delimiter)
			, _first_element(true)
		{

		}

		ostream_joiner(ostream_type& stream, DelimT&& delimiter)
			:_out_stream(std::addressof(stream))
			, _delimt(std::move(delimiter))
			, _first_element(true)
		{

		}

		ostream_joiner(const ostream_joiner& other) = default;
		ostream_joiner(ostream_joiner&& other) = default;

		template<class T>
		ostream_joiner& operator=(const T& value)
		{
			if(!_first_element)
				*_out_stream << _delimt;
			_first_element = false;
			*_out_stream << value;
			return *this;
		}

		ostream_joiner& operator=(const ostream_joiner& other) = default;
		ostream_joiner& operator=(ostream_joiner&& other) = default;

		ostream_joiner& operator*()noexcept{ return *this; }
		ostream_joiner& operator++()noexcept{ return *this; }
		ostream_joiner& operator++(int)noexcept{ return *this; }
	private:

		ostream_type*	_out_stream;
		DelimT			_delimt;
		bool			_first_element;
	};

	template <class charT, class traits, class DelimT>
	ostream_joiner<std::decay_t<DelimT>, charT, traits>
		make_ostream_joiner(std::basic_ostream<charT, traits>& os, DelimT&& delimiter)
	{
		return ostream_joiner<std::decay_t<DelimT>, charT, traits>(os, std::forward<DelimT>(delimiter));
	}


}

